from datetime import datetime

from openpyxl import load_workbook
import csv
import io


def get_client_ip(request):
    """
    从请求中获取客户端真实IP（支持代理）
    优先级：X-Forwarded-For（第一个非内部IP） > REMOTE_ADDR
    """
    ip = request.META.get('HTTP_X_FORWARDED_FOR', '').split(',')[0].strip()
    if not ip or ip in ('unknown', '127.0.0.1', '::1'):
        ip = request.META.get('REMOTE_ADDR', '0.0.0.0')
    return ip


# apps/common/utils.py
def get_file_extension(file_name: str) -> str:
    """
    安全获取文件扩展名（支持多后缀，如.tar.gz）
    返回小写扩展名（如 .XLSX → xlsx），无扩展名返回空字符串
    """
    if not file_name:
        return ''
    # 按最后一个点分割（处理多后缀）
    parts = file_name.rsplit('.', 1)
    if len(parts) == 1:
        return ''  # 无扩展名
    ext = parts[1].lower()
    # 过滤无效扩展名（如空字符串或纯数字）
    if not ext or ext.isdigit():
        return ''
    return ext


# -------------------- 辅助工具类 --------------------
class CSVParser:
    def __init__(self, file):
        self.file = file
        self.wb = load_workbook(file, read_only=True, data_only=True)
        self.ws = self.wb.active
        self.header = [c.value.strip() for c in self.ws[1] if c.value]
        self.decoder = io.TextIOWrapper(file, encoding='utf-8-sig')
        self.reader = csv.DictReader(self.decoder)
        # 传入 fieldnames 参数
        self._validate_header(self.reader.fieldnames)
        self.total_rows = self._count_valid_rows()  # 初始化总行数

    def _find_header_row(self) -> list:
        """动态查找第一个非空行作为表头（从第1行开始）"""
        for row_num in range(1, self.ws.max_row + 1):
            row = self.ws[row_num]
            cells = [c.value for c in row if isinstance(c.value, str) and c.value.strip()]
            if cells:  # 至少有一个非空字符串单元格
                self.header_row = row_num  # 记录表头行号
                return [c.value.strip() for c in row if c.value]  # 过滤空值
        raise ValueError("Excel 文件无有效表头行")  # 所有行全空

    def _validate_header(self, fieldnames):
        # 修复2：强制校验核心字段（如你的业务需要的"欠款金额"）
        """验证Excel文件表头是否符合要求"""
        # 检查字段是否存在
        missing_headers = ExcelParser.REQUIRED_HEADERS - set(fieldnames)
        if missing_headers:
            raise ValueError(
                f"缺少必填列：{', '.join(missing_headers)}，"
                "请确保包含以下列：集团名称, 最小账期, 最大账期, 全量欠费（元）,"
                "存量欠费（元）, 新增欠费（元）, 当前坏账（元）, 业务大类"
            )

    def chunk_iter(self, chunk_size=1000):
        """流式分块读取"""
        chunk = []
        for row in self.reader:
            chunk.append(row)
            if len(chunk) >= chunk_size:
                yield chunk
                chunk = []
        if chunk:
            yield chunk

    def _count_valid_rows(self) -> int:
        """统计有效数据行数（跳过标题，过滤全空行）"""
        row_count = 0
        for row in self.reader:
            if any(cell.strip() for cell in row.values()):  # 过滤全空行
                row_count += 1
        self.reader = csv.DictReader(self.decoder)  # 重置读取器
        return row_count


class ExcelParser:
    REQUIRED_HEADERS = {
        '集团名称', '最小账期', '最大账期',
        '全量欠费（元）', '存量欠费（元）',
        '新增欠费（元）', '当前坏账（元）',
        '业务大类'
    }

    def __init__(self, file):
        self.file = file
        self.wb = load_workbook(file, read_only=True, data_only=True)
        self.ws = self.wb.active
        self.header = [c.value.strip() for c in self.ws[1] if c.value]
        # 传入 fieldnames 参数
        self._validate_header(self.header)
        self.row_iter = self.ws.iter_rows(min_row=2, values_only=True)
        self.total_rows = self._count_valid_rows()  # 初始化总行数

    def _find_header_row(self) -> list:
        """动态查找第一个非空行作为表头（从第1行开始）"""
        for row_num in range(1, self.ws.max_row + 1):
            row = self.ws[row_num]
            cells = [c.value for c in row if isinstance(c.value, str) and c.value.strip()]
            if cells:  # 至少有一个非空字符串单元格
                self.header_row = row_num  # 记录表头行号
                return [c.value.strip() for c in row if c.value]  # 过滤空值
        raise ValueError("Excel 文件无有效表头行")  # 所有行全空

    def _validate_header(self, fieldnames):
        # 修复2：强制校验核心字段（如你的业务需要的"欠款金额"）
        """验证Excel文件表头是否符合要求"""
        # 检查字段是否存在
        missing_headers = ExcelParser.REQUIRED_HEADERS - set(fieldnames)
        if missing_headers:
            raise ValueError(
                f"缺少必填列：{', '.join(missing_headers)}，"
                "请确保包含以下列：集团名称, 最小账期, 最大账期, 全量欠费（元）,"
                "存量欠费（元）, 新增欠费（元）, 当前坏账（元）, 业务大类"
            )

    def chunk_iter(self, chunk_size=1000):
        """流式分块读取"""
        chunk = []
        for row in self.row_iter:
            row_dict = {self.header[i]: row[i] for i in range(len(self.header))}
            chunk.append(row_dict)
            if len(chunk) >= chunk_size:
                yield chunk
                chunk = []
        if chunk:
            yield chunk

    def _count_valid_rows(self) -> int:
        """统计有效数据行数（跳过标题，过滤全空行）"""
        row_count = 0
        for row in self.ws.iter_rows(min_row=2, values_only=True):
            if any(cell is not None and str(cell).strip() for cell in row):
                row_count += 1
        return row_count

    # -------------------- 数据校验工具 --------------------
    @staticmethod
    def _parse_date(value):
        """Excel日期+多格式解析（无异常抛出）"""
        if isinstance(value, (int, float)) and 25569 < value < 59999:
            return datetime.fromordinal(datetime(1900, 1, 1).toordinal() + int(value) - 2).date()
        for fmt in ['%Y-%m', '%Y年%m月', '%Y/%m']:
            try:
                return datetime.strptime(str(value).strip(), fmt).date()
            except:
                continue
        return None  # 由上层校验处理

    @staticmethod
    def _parse_amount(value):
        """安全金额解析（返回None表示无效）"""
        if isinstance(value, str):
            value = value.replace('￥', '').replace(',', '').strip()
        try:
            return round(float(value), 2) if value else 0.0
        except:
            return None


# -------------------- 辅助类 --------------------
class ArrearsImportError:
    def __init__(self, row, message, raw_data):
        self.row = row
        self.message = message
        self.raw_data = raw_data
